/*
 * init.c
 *
 *  Created on: 17 sept. 2013
 *      Author: the
 */
#include "init.h"
int nbPerLine;//use for the grid topology (indicates the number of nodes per line).
float edgeLength;//use for the grid topology (indicates the length of a link).

void error(char* string)
{
	perror(string);
	exit(-1);
}//end of function error()

//Initialize the different entries of the node "id".
//variant=0: nodes are randomly scattered in the area
//variant=1: nodes form a grid with degree 4 (for nodes in teh midlle, less on the edge of course).
void initNode(int id, int variant)
{
	int i;

	nodes[id].id=id;
	nodes[id].nbOfRadios=nbOfRadios;
	nodes[id].nbN1=-1;
	nodes[id].nbN2=-1;
	nodes[id].routeFlag=0;

	//Set the node location
	if(variant==0){
		if(id==0)
		{
			nodes[id].x=10.0;
			nodes[id].y=10.0;
		}

		if(id==nbOfNodes-1)
		{
			nodes[id].x=L-10.0;
			nodes[id].y=L-10.0;
		}
		if( id!=0 && id!=nbOfNodes-1)
		{
			nodes[id].x=L*(1.0*rand())/(1.0*RAND_MAX);
			nodes[id].y=L*(1.0*rand())/(1.0*RAND_MAX);
		}
	}

	if(variant==1){
		nodes[id].x=edgeLength*(id%nbPerLine);
		nodes[id].y=edgeLength*floor((1.0*id)/(1.0*nbPerLine));
	}

	//Assign frequency -1 to all radios
	for(i=0;i<MAX_FREQ;i++){
		nodes[id].frequency[i]=-1;
	}

    	//Set the neighorhood and the 2-neighborhood with -1 (it means not assigned).
	for(i=0;i<MAX_N1;i++){
		nodes[id].N1[i].id=-1;
		nodes[id].N1[i].nbOfRadios=nbOfRadios;
		nodes[id].N1[i].frequency=-1;
	}

	for(i=0;i<MAX_N2;i++){
		nodes[id].N2[i].id=-1;
		nodes[id].N2[i].nbOfRadios=nbOfRadios;
		nodes[id].N2[i].frequency=-1;
	}

	//initializes the routing table
	initRoutingTable(id);

}//end of function initNode()

//Malloc the ressource for the routing table and initialize it (with -1)
struct routingEntry* initRoutingTable(int id)
{
	int i;
	struct routingEntry* ptrRoutingTable;

	if((ptrRoutingTable=(struct routingEntry *) malloc(nbOfNodes*sizeof(struct routingEntry)))==NULL)
		error("Error: initRoutingTable() -> malloc");

	nodes[id].routingTable=ptrRoutingTable;
	//printf("--MALLOC-- Adresse routingTable %d: %x\n",id,nodes[id].routingTable);
	for(i=0;i<nbOfNodes;i++)
	{
		ptrRoutingTable[i].destination=-1;
		ptrRoutingTable[i].nextHop=-1;
		//ptrRoutingTable[i].radio=-1;
		//ptrRoutingTable[i].frequency=-1;
	}

	return(ptrRoutingTable);
}//end of function initRoutingTable()

//Free the ressource (the two mallocs) for node id
void freeNodes()
{
	int i;

	for(i=0;i<nbOfNodes;i++){
		//printf("--FREE-- Adresse routingTable %d: %x\n",i,nodes[i].routingTable);
		free(nodes[i].routingTable);
	}
	//printf("--FREE-- Nodes: %x\n",nodes);
	//free(nodes);//Done in the main
}

//indicates if the node id1 is in the neighborhood of node id2
//return 1 if yes and 0 otherwise
int isNeighbor(int id1, int id2)
{
    if (((pow((nodes[id1].x-nodes[id2].x),2) + pow((nodes[id1].y-nodes[id2].y),2))<=pow(R,2))&&(id1!=id2)) return 1;
    else return 0;
}

//indicates if the node id1 is in the 2-neighborhood of node id2
//return 1 if yes and 0 otherwise
int is2Neighbor(int id1, int id2)
{
    int i,k;
    //If id1=id2 or they are neighbor, then they are NOT 2-hop neighbor (return 0)
    if ((id1==id2)||(isNeighbor(id1,id2))) return 0;
    for (i=0;i<nodes[id2].nbN1;i++)
    {
    	k=nodes[id2].N1[i].id;
   	//If we find a common neighbor, they are 2-hop neighbor, return 1
	if (isNeighbor(id1,k)) return 1;
    }
    return 0;
}

int getMetric(int id1, int id2)
{
	double distance= sqrt( pow((nodes[id1].x-nodes[id2].x),2.0) + pow((nodes[id1].y-nodes[id2].y),2.0) );

	if(distance < 0.0)
	{
		fprintf(stderr,"Error in fct getMetric(): distance between two nodes is less than 0.0 (=%e) - abort...\n",distance);
		exit(2);
	}

	// The Anh a mis a jour en fonction IdealWifiManager (voir le fichier rounde_idealwifimanager.ods)
	// Mofifier le 23/9/2013
	if(distance <= 24) return (24);
	if(distance <= 25) return (23);
	if(distance <= 28) return (22);
	if(distance <= 29) return (20);
	if(distance <= 40) return (19);
	if(distance <= 41) return (18);
	if(distance <= 42) return (17);
	if(distance <= 51) return (15);
	if(distance <= 52) return (14);
	if(distance <= 53) return (13);
	if(distance <= 69) return (12);
	if(distance <= 70) return (11);
	if(distance <= 86) return (9);
	if(distance <= 88) return (8);
	if(distance <= 89) return (6);
	if(distance <= 110) return (5);
	if(distance <= 113) return (4);
	if(distance <= 114) return (3);
	if(distance <= 115) return (2);
	if(distance <= 117) return (1);
	// Fin-The Anh


	return(0.0);
}


//Update the neighborhood for node id (on the common channel)
int updateN1(int id)
{
    int i,j=0;
    for(i=0;i<nbOfNodes;i++)
    {
            if (isNeighbor(i,id))
            {
	    	//Add i to the list of neighbors
                nodes[id].N1[j].id=i;
		nodes[id].N1[j].nbOfRadios=nbOfRadios;
		nodes[id].N1[j].frequency=-1;//Not allocated
		nodes[id].N1[j].radio=-1;//Not allocated
		nodes[id].N1[j].metric=getMetric(id,i);
                j++;
            }
	    if(j>=MAX_N1){
		fprintf(stderr,"Error updateN1 (init.c): the value of the constant MAX_N1 is not sufficently large\n");
		exit(-1);
	    }
    }//end of for

    nodes[id].nbN1=j;
    nodes[id].frequency[0]=0;

    return(1);
}//end of function updateN1()

//Update the 2-neighborhood for node id (on the common channel)
int updateN2(int id)
{
	int i,j=0;
	for(i=0;i<nbOfNodes;i++)
	{
		if (is2Neighbor(i,id))
		{
			//Add i to the list of 2-neighbors
			nodes[id].N2[j].id=i;
			nodes[id].N2[j].nbOfRadios=nbOfRadios;
			nodes[id].N2[j].frequency=0;
			j++;
       		}
        	if(j>=MAX_N2){
         		fprintf(stderr,"Error updateN2 (init.c): the value of the constant MAX_N2 is not sufficiently large\n");
			exit(-1);
	  	}
	}
	nodes[id].nbN2=j;
	nodes[id].frequency[0]=0;

	return(1);
}//end of function updateN2()

//Initialize the array nodes (id, locations, N1 and N2) and allocate the memory for the routing table.
//Frequency are not assigned and the routing table is not compute.
void initArrayNodes(int variant)
{
	int i;

	if((variant!=0)&&(variant!=1)){
		fprintf(stderr,"Bad choice of topology: it must be 0 or 1.\n");
		exit(-1);
	}

	//In case of the grid topology, we fix the link lengths and the number of nodes per line.
	if(variant==1){
		//We must have a square for the grid
		nbPerLine=(int) floor(sqrt(1.0*nbOfNodes));
		nbOfNodes=nbPerLine*nbPerLine;

		//The edgeLength must be edgeLength*sqrt(2)>R and edgeLength<R in order to get a degree of 4.
		edgeLength=0.5*R*(1.0/sqrt(2.0)+1.0);

		//We modify L
		L=edgeLength*(nbPerLine-1);

		fprintf(stderr,"nbOfNodes=%d edgeLength=%f nbPerLine=%d edgeLength=%f\n",nbOfNodes,edgeLength,nbPerLine,edgeLength);
	}

	for(i=0;i<nbOfNodes;i++) initNode(i,variant);
	for(i=0;i<nbOfNodes;i++) updateN1(i);
	for(i=0;i<nbOfNodes;i++) updateN2(i);

	//DEBUG
 	//printArrayNodes();

}//end of function initArrayNode()

//Print the fields of the nodes in the array nodes
void printArrayNodes()
{
	int i,j,index;

	for(i=0;i<nbOfNodes;i++)
	{
		printf("---------- Node %d -----------\n",i);
		printf("-- x=%f y=%f\n",nodes[i].x,nodes[i].y);
		printf("-- nbOfRadios=%d nbN1=%d nbN2=%d Frequency=",nodes[i].nbOfRadios,nodes[i].nbN1,nodes[i].nbN2);
		for(j=0;j<nodes[i].nbOfRadios;j++) printf("%d ",nodes[i].frequency[j]); printf("\n");
		printf("-- N1 = "); for(j=0;j<nodes[i].nbN1;j++) printf("%d ",nodes[i].N1[j].id); printf("\n");
		printf("-- N2 = "); for(j=0;j<nodes[i].nbN2;j++) printf("%d ",nodes[i].N2[j].id); printf("\n");
		printf("-- Routing Table: dest / nextHop / cost / radio /frequency\n");
		for(j=0;j<nbOfNodes;j++)
		{
			index=getIndexN1(nodes[i],j);

			//nodes[id].N1[index].frequency=bestFreq;
			//nodes[id].N1[index].radio=bestRadioId;
			printf("%d / %d / %d / ",nodes[i].routingTable[j].destination,nodes[i].routingTable[j].nextHop,nodes[i].routingTable[j].cost);
			if(index>=0) printf("%d / %d\n",nodes[i].N1[index].radio,nodes[i].N1[index].frequency);
			else printf("-1 / -1\n");
		}
	}

}//end of function printArrayNodes()

